package com.narata.netty.protocol;

import com.narata.netty.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * @Author: XJL
 * @Description:
 * @Date: Create in 22:38 2022-05-11
 * @Modified By: 必须和LengthFieldBasedFrameDecoder对象一起使用，确保接收到的ByteBuf消息是完整的
 **/
@Slf4j
@ChannelHandler.Sharable
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> list) throws Exception {
        ByteBuf out = ctx.alloc().buffer();
        // （1）写入4个字节的魔术
        out.writeBytes(new byte[]{1,2,3,4});

        // （2）写入1个字节的版本
        out.writeByte(1);

        // （3）写入1个字节，表示序列化的方式 0表示jdk 1表示 json
        out.writeByte(0);

        // （4）写入1个字节的指令类型
        out.writeByte(msg.getMessageType());

        // （5）写入4个字节的请求序列号
        out.writeInt(msg.getSequenceId());

        // （6）写入1个字节的填充字节，使请求头满足2的幂
        out.writeByte(0xff);

        // （7）写入消息的长度
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] bytes = Serializer.Algorithm.Java.serialize(msg);
        out.writeInt(bytes.length);
        // （8）写入消息
        out.writeBytes(bytes);
        list.add(out);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        int magicNum = in.readInt();

        byte version = in.readByte();

        byte serializerType = in.readByte();
        byte messageType = in.readByte();
        int sequencdId = in.readInt();
        in.readByte();
        int length = in.readInt();
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);

        Class<?> messageClass = Message.getMessageClass(messageType);
        Object message = Serializer.Algorithm.Java.deserialize(messageClass, bytes);
        log.debug("magicNum:{},version:{},serializerType:{},messageType:{},sequencdId:{},length:{}", magicNum, version, serializerType, messageType, sequencdId, length);
        log.debug("message: {}", message);

        out.add(message);

    }
}
